(library (utils)
(export assocr assoc-replace map* mapply removes merge-cons every length=? length>=? length>? concatenate read-from-file atomic? print define/debug)
(import (rnrs) (rnrs lists (6)))

(define (assocr tbl k) (cdr (assoc k tbl)))

(define (assoc-replace tbl key val)
  (if (null? tbl)
      '()
      (let ((entry (car tbl)))
        (if (eq? (car entry) key)
            (cons (cons key val) (cdr tbl))
            (cons entry (assoc-replace (cdr tbl) key val))))))

(define (map* f l)
  (if (null? l)
      '()
      (let* ((h (f (car l))) (t (map* f (cdr l)))) (cons h t))))

(define-syntax mapply
  (syntax-rules ()
    ((mapply f xs arg ...)
     (map* (lambda (x) (f x arg ...)) xs))))

(define (removes things list)
 ;; remove each one of the things from the list
 (if (null? things) list (removes (cdr things) (remove (car things) list))))

(define (merge-cons x xs)
 (if (member x xs) xs (cons x xs)))

(define every for-all)

(define (length=? l n)
  (if (= 0 n)
      (null? l)
      (if (null? l)
          #f
          (length=? (cdr l) (- n 1)))))

(define (length>=? l n)
  (cond ((null? l) (= 0 n))
        ((= 0 n) #t)
        (else (length>=? (cdr l) (- n 1)))))

(define (length>? l n) (length>=? l (+ n 1)))

(define (concatenate lists) (apply append lists))

(define (read*)
 (let ((f (read)))
  (if (eof-object? f) '() (cons f (read*)))))

(define (read-from-file path)
 (with-input-from-file path read*))

(define (atomic? exp)
 (or (boolean? exp) (number? exp) (char? exp) (string? exp)))

(define (print x) (display x) (newline))

(define-syntax define/debug
  (syntax-rules ()
    ((define/debug (<name> <arg> ...) <body> ...)
     (define (<name> <arg> ...)
       (print `(debugging <name> ,<arg> ...))
       <body> ...))))

)

